package com.newgrand.annexserver.datasource;

import com.alibaba.druid.pool.DruidDataSource;
import com.newgrand.annexcommon.constant.DBUserTypeConstants;
import com.newgrand.annexcommon.model.DbConfigEnity;
import com.newgrand.annexserver.context.ApplicationContextHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import java.lang.reflect.Field;
import java.util.Map;

/**
 * @author ：minyang
 * @date ：Created in 2019/9/7 21:02
 */
public class NgDynamicDataSourceBeanRegistry {

    private final static Logger logger = LoggerFactory.getLogger(NgDynamicDataSourceBeanRegistry.class);

    private static DefaultListableBeanFactory beanFactory;

    public static void updateDynamicDataSource(DbConfigEnity entity) {
        getBeanFactory();
        String beanName = generateNgBeanName(entity);
        //判断spring中是否已经注册该bean
        if (isBeanSpringRegisterd(beanName)) {
            destroySpringBean(beanName);
        }
        //spring中注册该bean
        registerSpringBean(entity, beanName);

        AbstractRoutingDataSource dataSource = beanFactory.getBean("ngDynamicDataSource", NgDynamicRoutingDataSource.class);
        try {
            Field field = dataSource.getClass().getSuperclass().getDeclaredField("targetDataSources");
            field.setAccessible(true);
            Map<Object, Object> dataSourceMap = null;
            dataSourceMap = (Map<Object, Object>) field.get(dataSource);
            //动态数据源中包含该bean
            if (dataSourceMap.containsKey(beanName)) {
                dataSourceMap.remove(beanName);
            }

            setDataSource(beanName, dataSource, field, dataSourceMap, beanName);


        } catch (Exception e) {
            logger.error("updateDynamicDataSource", e);
        }
    }

    //设置动态数据源
    private static void setDataSource(String beanName, AbstractRoutingDataSource dataSource, Field field,
                                      Map<Object, Object> dataSourceMap, String dataSourceKey) throws IllegalAccessException {
        DruidDataSource dds = beanFactory.getBean(beanName, DruidDataSource.class);
        dataSourceMap.put(dataSourceKey, dds);
        field.set(dataSource, dataSourceMap);
        dataSource.afterPropertiesSet();
    }

    //往spring中注册bean
    private static void registerSpringBean(DbConfigEnity entity, String beanName) {
        logger.info("registerSpringBean {}", entity);

        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(DruidDataSource.class);
        beanDefinition.setDestroyMethodName("close");
        beanDefinition.setInitMethodName("init");

        MutablePropertyValues mpv = beanDefinition.getPropertyValues();
        mpv.addPropertyValue("url", entity.getUrl());
        mpv.addPropertyValue("username", entity.getUsername());
        mpv.addPropertyValue("password", entity.getPassword());
        mpv.addPropertyValue("driverClassName", entity.getDriverClassName());
        beanFactory.registerBeanDefinition(beanName, beanDefinition);
    }

    //spring中是否注册该bean
    private static boolean isBeanSpringRegisterd(String beanName) {
        return beanFactory.containsBean(beanName);
    }

    private static void getBeanFactory() {
        if (beanFactory == null) {
            ConfigurableApplicationContext context = (ConfigurableApplicationContext) ApplicationContextHolder.getContext();
            beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
        }
    }

    public static String generateNgBeanName(DbConfigEnity entity) {
        if (entity.getdBUserType() == DBUserTypeConstants.business_type) {
            return DBUserTypeConstants.bean_name_business_type_pre + DBUserTypeConstants.separtor + entity.getDbtoken().toUpperCase();
        } else {
            return DBUserTypeConstants.bean_name_store_type_pre + DBUserTypeConstants.separtor + entity.getDbtoken().toUpperCase();
        }
    }

    //销毁spring中注册的bean
    private static void destroySpringBean(String beanName) {
        String[] beanNames = beanFactory.getBeanNamesForType(DruidDataSource.class, true, false);
        for (String bean : beanNames) {
            if (beanName.equals(bean)) {
                beanFactory.removeBeanDefinition(bean);
            }
        }
    }


}
